#include<iostream>
#include<functional>
#include<string>
#include<cstring>
#include<ctime>
#include<unordered_map>

#include"Log.hpp"
#include"Socket.hpp"
#include"Epoll.hpp"
#include"Protocol.hpp"

class TcpServer;
class Connection;

using func_t =std::function<void(Connection*)>;//回调函数类型
using callback_t =std::function<void(Connection*,std::string &request)>;//回调函数类型

class Connection//保存所有和连接/读写相关的类
{
public:
    Connection(int sock=-1)
        :_sock(sock),_tsvr(nullptr)
    {}
    void SetCallback(func_t recv_cb,func_t send_cb,func_t except_cb)
    {
        _recv_cb = recv_cb;
        _send_cb = send_cb;
        _except_cd = except_cb;
    }
    ~Connection()
    {}

public:
    int _sock;//I/O文件描述符
    func_t _recv_cb;//读回调函数
    func_t _send_cb;//写回调函数
    func_t _except_cd;//异常回调函数
    std::string _in_buffer;//输入缓冲区
    std::string _out_buffer;//输出缓冲区
    TcpServer* _tsvr;//服务器回指指针
    time_t _last_time;//记录上次读写时间
};
class TcpServer
{
    const static int default_port = 8081;
    const static int g_num=128;
    const static int link_timeout = 5;
public:
    TcpServer(int port = default_port)
        :_port(port),_nrevs(g_num)
    {
        //获取listensock
        _listensock= Sock::Socket();
        Sock::Bind(_listensock,_port);
        Sock::Listen(_listensock);
        //创建epoll实例
        _epoll.Create();
        //将listensock添加到epoll中
        AddConnection(_listensock,std::bind(&TcpServer::Accepter,this,std::placeholders::_1),nullptr,nullptr);
        logMessage(DEBUG,"add listensock[%d] to epoll success..",_listensock);
        //创建保存就绪队列的数组
        _revs = new struct epoll_event[_nrevs];
    }
    void AddConnection(int sock,func_t recv_cb,func_t send_cb,func_t except_cb)
    {
        //设置sock为非阻塞
        Sock::SetNonBlock(sock);
        //构建Connection对象,封装sock
        Connection* conn = new Connection(sock);
        conn->SetCallback(recv_cb,send_cb,except_cb);
        conn->_tsvr = this;
        //让epoll对象监视
        _epoll.Add(sock,EPOLLIN|EPOLLET);
        //将conn对象保存到unordered_map中
        _connections.insert(std::make_pair(sock,conn)); 
    }
    void Accepter(Connection* conn)
    {
        while(true)
        {
            std::string client_ip;
            uint16_t client_port;
            int accept_errno=0;
            int sock=Sock::Accept(conn->_sock,&client_ip,&client_port,&accept_errno);
            if(sock<0)
            {
                if(accept_errno==EAGAIN||accept_errno==EWOULDBLOCK)
                    break;
                else if(accept_errno==EINTR)
                    continue;
                else
                {
                    logMessage(WARNING,"accept error...code[%d]:%s",accept_errno,strerror(accept_errno));
                    break;
                }
            }
            if(sock>=0)
            {
                AddConnection(sock,std::bind(&TcpServer::Recver,this,std::placeholders::_1),
                                   std::bind(&TcpServer::Sender,this,std::placeholders::_1),
                                   std::bind(&TcpServer::Excepter,this,std::placeholders::_1));
                //logMessage(DEBUG,"add client[%s:%d]success, add to epoll of TcpServer success, sock: %d",client_ip.c_str(),client_port,sock);
                printf("add client[%s:%d]success, add to epoll of TcpServer success, sock: %d\n",client_ip.c_str(),client_port,sock);
            }
        }
    }
    
    void Recver(Connection* conn)
    {
        conn->_last_time=std::time(nullptr);
        const int num=1024;
        bool err=false;
        while(true)
        {
            char buf[num];
            ssize_t n=recv(conn->_sock,buf,sizeof(buf)-1,0);
            if(n<0)
            {
                if(errno==EAGAIN||errno==EWOULDBLOCK)
                    break;
                else if(errno==EINTR)
                    continue;
                else
                {
                    logMessage(ERROR,"recv error...code[%d]:%s",errno,strerror(errno));
                    conn->_except_cd(conn);
                    err=true;
                    break;
                }
            }
            else if(n==0)
            {
                logMessage(DEBUG,"client disconnect,sock[%d] close...",conn->_sock);
                conn->_except_cd(conn);
                err=true;
                break;
            }
            else
            {
                buf[n]='\0';
                conn->_in_buffer+=buf;
            }
        }
        if(!err)
        {
            logMessage(DEBUG,"client[%d]>>>%s",conn->_sock,conn->_in_buffer.c_str());
            std::vector<std::string> message;
            SpliteMessage(conn->_in_buffer,&message);
            for(auto& msg:message)
                _cb(conn,msg);
        }
    }
    void EnableReadWrite(Connection* conn,bool readable,bool writeable)
    {
        uint32_t events=((readable?EPOLLIN:0)|(writeable?EPOLLOUT:0));
        bool res=_epoll.Ctrl(conn->_sock,events);
        if(!res)
        {
            logMessage(ERROR,"EnableReadWrite() erro...code[%d]:%s",errno,strerror(errno));
            return;
        }
    }
    void Sender(Connection* conn)
    {
        while(true)
        {
            ssize_t n=send(conn->_sock,conn->_out_buffer.c_str(),conn->_out_buffer.size(),0);
            if(n>0)
            {
                conn->_out_buffer.erase(0,n);//删除已经发送的数据
                //发送成功
                if(conn->_out_buffer.empty())
                    break;
            }
            else
            {
                if(errno==EAGAIN||errno==EWOULDBLOCK)
                    break;
                else if(errno==EINTR)
                    continue;
                else
                {
                    logMessage(ERROR,"send error...code[%d]:%s",errno,strerror(errno));
                    conn->_except_cd(conn);
                    break;
                }
            }
        }
        if(conn->_out_buffer.empty())
            EnableReadWrite(conn,true,false);
        else
            EnableReadWrite(conn,true,true);
    }
    void Excepter(Connection* conn)//异常处理函数
    {
        int err_sock=conn->_sock;
        if(!IsConnectionExist(conn->_sock))
            return;
        bool res=_epoll.Del(conn->_sock);
        if(!res)
        {
            logMessage(ERROR,"delete from epoll error...code[%d]:%s",errno,strerror(errno));
        }
        _connections.erase(err_sock);
        close(err_sock);
        delete conn;
        logMessage(DEBUG,"for sock[%d] called Excepter() Ok...",err_sock);
    }
    bool IsConnectionExist(int sock)
    {
        auto iter=_connections.find(sock);
        if(iter==_connections.end())
            return false;
        else
            return true;
    }
    void LoopOnce()
    {
        int n=_epoll.Wait(_revs,_nrevs);
        if(n==_nrevs)
        {
            struct epoll_event *new_revs;
            int new_nfds=_nrevs*2;
            _revs=new struct epoll_event[new_nfds];
            memcpy(new_revs,_revs,sizeof(struct epoll_event)*_nrevs);
            delete [] _revs;
            _revs=new_revs;

        }
        for(int i=0;i<n;++i)
        {
            int sock = _revs[i].data.fd;
            uint32_t revents = _revs[i].events;
            //根据事件类型不同调用不同的回调函数
            //错误
            if(revents & EPOLLERR)
                revents |=(EPOLLIN|EPOLLOUT);
            //对端关闭连接
            if(revents & EPOLLHUP)
                revents |=(EPOLLIN|EPOLLOUT);
            //读事件就绪
            if(revents & EPOLLIN)
            {
                if(IsConnectionExist(sock)&&_connections[sock]->_recv_cb!=nullptr)//回调函数被设置才调用
                {
                    _connections[sock]->_recv_cb(_connections[sock]);//调用读回调函数
                }
            }
            //写事件就绪
            if(revents & EPOLLOUT)
            {
                if(IsConnectionExist(sock)&&_connections[sock]->_send_cb!=nullptr)
                {
                    _connections[sock]->_send_cb(_connections[sock]);//调用写回调函数
                }
            }
        }
    }
    void ConnectAliveCheck()
    {
        for(auto &connection:_connections)
        {
            time_t current_time=time(nullptr);
            if(connection.second->_sock!=connection.first)//监听套接字不检查
                if(current_time-connection.second->_last_time<link_timeout)//超时
                continue;
                else
                {
                    if(connection.first!=_listensock&&connection.second!=nullptr&&(_connections.find(connection.first)!=_connections.end()))//连接存在
                        Excepter(connection.second);
                }
        }
    }
    void Dispather(callback_t cb)
    {
        _cb=cb;
        while(true)
        {
            LoopOnce();
            ConnectAliveCheck();
        }
    }
    ~TcpServer()
    {
        if(_listensock>=0)
            close(_listensock);
        _epoll.Close();
        if(_revs)
            delete [] _revs;
    }
private:
    uint16_t _port;//端口号
    int _listensock;//监听套接字描述符
    Epoll _epoll;//epoll实例
    struct epoll_event *_revs;//保存从就绪队列中取出的事件的数组
    int _nrevs;//就绪队列中事件的数量
    std::unordered_map<int,Connection*> _connections;//保存所有连接
    callback_t _cb;//上层设置的业务处理函数

};